package com.hibase.core.rule.utils;

import cn.hutool.core.date.DateUtil;
import com.hibase.core.rule.entity.ruledebug.HibaseRuleDebugLog;
import com.hibase.core.rule.entity.ruledebug.RuleDebugResultVO;
import com.ql.util.express.DefaultContext;
import com.ql.util.express.DynamicParamsUtil;
import com.ql.util.express.ExpressRunner;
import com.ql.util.express.IExpressContext;
import com.ql.util.express.config.QLExpressRunStrategy;
import com.ql.util.express.instruction.op.OperatorAnonymousNewList;
import com.ql.util.express.instruction.op.OperatorAnonymousNewMap;
import com.ql.util.express.instruction.op.OperatorMinMax;
import com.ql.util.express.instruction.op.OperatorOr;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

/**
 *  规则引擎操作工具类
 *  @author kevinlong
 *  @since 2019-04-17
 */
@Deprecated
public class HibaseRuleEngineUtils_old {

    private static final HibaseRuleDebugLog log = new HibaseRuleDebugLog(LoggerFactory.getLogger(HibaseRuleEngineUtils_old.class));


    private static class HibaseExpressSingletonHolder{

        private static ExpressRunner instance = null;

        public static ExpressRunner getRuleEngine() throws Exception{

            if(instance == null){
                // 禁止调用不安全的方法
                QLExpressRunStrategy.setForbiddenInvokeSecurityRiskMethods(Boolean.TRUE);
                instance = new ExpressRunner(true, true);
                //采用不定参数
                DynamicParamsUtil.supportDynamicParams = true;

                instance.addOperatorWithAlias("取模","mod", null);
                instance.addOperatorWithAlias("包含","in", null);
                instance.addOperatorWithAlias("遍历","for", null);
                instance.addOperatorWithAlias("如果","if", null);
                instance.addOperatorWithAlias("当","when", null);
                instance.addOperatorWithAlias("则","then", null);
                instance.addOperatorWithAlias("否则","else", null);
                instance.addOperatorWithAlias("创建全局别名","exportAlias", null);
                instance.addOperatorWithAlias("创建别名","alias", null);
                instance.addOperatorWithAlias("结束遍历","break", null);
                instance.addOperatorWithAlias("跳出当前遍历","continue", null);
                instance.addOperatorWithAlias("返回","return", null);
                instance.addOperatorWithAlias("定义宏","macro", null);
                instance.addOperatorWithAlias("定义方法","function", null);
                instance.addOperatorWithAlias("创建变量","def", null);
                instance.addOperatorWithAlias("创建全局变量","exportDef", null);
                instance.addOperatorWithAlias("创建","new", null);
                instance.addOperatorWithAlias("数组","array", null);
                instance.addOperatorWithAlias("匿名数组","anonymousNewArray", null);
                instance.addOperatorWithAlias("模糊","like", null);
                instance.addOperatorWithAlias("打印","println", null);
                instance.addOperatorWithAlias("小于","<","$1 小于 $2");
                instance.addOperatorWithAlias("小于等于","<=","$1 小于等于 $2");
                instance.addOperatorWithAlias("大于",">","$1 小于 $2");
                instance.addOperatorWithAlias("大于等于",">=","$1 大于等于 $2");
                instance.addOperatorWithAlias("不等于","!=","$1 不等于 $2");
                instance.addFunctionOfClassMethod("取绝对值", Math.class.getName(), "abs",
                        new String[] { "double" }, null);
//                instance.addFunctionOfClassMethod("转换为大写", StringUtils.class.getName(),
//                        "upperCase", new String[] { "String" }, null);
//                instance.addFunctionOfClassMethod("转换为小写", StringUtils.class.getName(),
//                        "lowerCase", new String[] { "String" }, null);
                instance.addFunction("创建对象", new OperatorAnonymousNewMap("创建对象"));
                instance.addFunction("创建数组", new OperatorAnonymousNewList("创建数组"));
                instance.addOperator("取最小值", new OperatorMinMax("min"));
                instance.addOperator("取最大值", new OperatorMinMax("max"));
                instance.addOperator("或者", new OperatorOr("或者"));
                instance.addOperatorWithAlias("且","&&","$1 且 $2");
                instance.addOperatorWithAlias("或","或者","$1 或 $2");

                //得到当前时间戳
                instance.addFunctionOfClassMethod("得到当前时间戳", DateUtil.class.getName(),"current", new String[] { "boolean" },null);
                //字符串转时间戳
                instance.addFunctionOfClassMethod("字符串转时间戳", DateUtils.class.getName(),"timestamp", new Class[] { String.class,String.class },null);
                //时间戳比较大小
                instance.addFunctionOfClassMethod("时间戳比较", DateUtils.class.getName(),"compare", new String[] { "long","long" },null);

                //TODO:动态加载指定路径文件夹中的方法
//                for(){
//                    instance.addFunctionOfClassMethod("取绝对值", Math.class.getName(), "abs",
//                            new String[] { "double" }, null);
//                }
                instance.addFunctionOfClassMethod("查询数据源", HibaseRuleCallSqlUtils.class.getName(), "executeSelectSql",
                        new Class[]{String.class,Object[].class}, null);
            }
            return instance;
        }
    }

    private HibaseRuleEngineUtils_old(){

    }

    /**
     * 测试编译规则
     */
    public static void testBuildRule(String ruleString) throws Exception{
        HibaseExpressSingletonHolder.getRuleEngine().parseInstructionSet(ruleString);
    }

    /**
     * 执行规则
     * @return
     */
    public static Object executeRule(String ruleString, IExpressContext<String, Object> paramsMap) throws Exception{
        //关闭逻辑短路提高执行效率
        HibaseExpressSingletonHolder.getRuleEngine().setShortCircuit(true);
        //开启全局动态参数开关
        //DynamicParamsUtil.supportDynamicParams = true;
        return HibaseExpressSingletonHolder.getRuleEngine().execute(ruleString, paramsMap, null, true, true,log);
    }

    /**
     * 按调试模式执行规则
     * @return
     */
    public static RuleDebugResultVO executeRuleByDebug(String ruleString, IExpressContext<String, Object> paramsMap) throws Exception{

        //开启逻辑短路提高执行效率
        HibaseExpressSingletonHolder.getRuleEngine().setShortCircuit(false);
        Object result = HibaseExpressSingletonHolder.getRuleEngine().execute(ruleString, paramsMap, null, true, true, log);
        List<String> debugLog = new ArrayList<>(log.getDebugList());
        log.clear();
        // 组装 结果和日志
        RuleDebugResultVO ruleDebugResultVO = new RuleDebugResultVO();
        ruleDebugResultVO.setDebugLog(debugLog);
        ruleDebugResultVO.setResult(result);
        return ruleDebugResultVO;
    }


    public static void main(String[] args) throws Exception {
//        final String ruleString = "键值对对象1 = 创建对象(); " +
//                "键值对对象1.序号=1; " +
//                "键值对对象1.代码='2'; " +
//                "键值对对象2 = 创建对象(); " +
//                "键值对对象2.序号=3; " +
//                "键值对对象2.代码='4'; " +
//                "打印(键值对对象1); " +
//                "打印(键值对对象2);";

        final String ruleString = "测试值1 = 1;" +
                "测试值2 = 2;" +
                "打印((测试值1 大于 测试值2) + 'false'); " +
                "打印((测试值1 大于等于 测试值2) + 'false'); " +
                "打印((测试值1 小于 测试值2) + 'true'); " +
                "打印((测试值1 小于等于 测试值2) + 'true'); " +
                "打印((测试值1 > 测试值2) + 'false'); " +
                "打印((测试值1 < 测试值2) + 'true'); " +
                "打印((测试值1 != 测试值2) + 'true'); " +
                "打印((测试值1 不等于 测试值2) + 'true'); " +
                "打印((测试值1 大于 测试值2) 且 (测试值1 大于 测试值2)); " +
                "打印((测试值1 大于 测试值2) 或 (测试值1 大于 测试值2)); " +
                "打印((测试值1 大于 测试值2) && (测试值1 大于 测试值2)); " +
                "打印((测试值1 大于 测试值2) || (测试值1 大于 测试值2)); " +
                "返回 测试值2;";

        final String ruleStringExcSql = "测试值=查询数据源('SELECT max(t.id) FROM tms_dictionary t WHERE ${1}=${2}','1','1');" +
                "返回 测试值;";


        String testStr = "当前时间 = 得到当前时间戳(false);\n" +
                "打印(当前时间);";
        DefaultContext<String, Object> context = new DefaultContext<>();
        context.put("参数1",5);

        Object r = HibaseRuleEngineUtils_old.executeRuleByDebug(testStr, context);
        log.info("args = [" + args + "]");
        log.info("11111111111" + r);
    }

}
